#include "Scene.h"
#include "Sprite.h"
#include "ThorSceneManager.h"
#include "EffectManager.h"
#include "EffectBase.h"


using namespace Ogre;

extern OgreCanvas * gc;


Scene::Scene(Ogre::SceneManager * _sm, Ogre::Camera * _c)
{
	m_pSceneMgr = _sm;
	m_pCamera = _c;
	
	m_IOData = IOData(0,0,0,0,false);

	ThorSceneManager::getInstance()->registerCurrentScene(this);

	
}


Scene::~Scene()
{
	delete dynamicsWorld;
	delete solver;
	delete dispatcher;
	delete collisionConfiguration;
}

void Scene::load()
{
	_setupCamera();//same as below
	_createBackGround();//same as below
	_createSprites(); //should be read from static configuration

	EffectManager::getInstance()->setParNeeded(m_pSceneMgr, m_pCamera);
	EffectManager::getInstance()->createEffect(Ogre::UTFString("effect1"),
		EffectManager::EFT_STORMLIGHTNING);

	
}

void Scene::init()
{
	_createFxWorld();

}

void Scene::eventClick(int _xx, int _yy)
{
	std::map<Ogre::String,Sprite*>::iterator it;
	for(it = m_vNpc.begin(); it != m_vNpc.end(); ++it)
	{
		if(it->second)
			it->second->eventClick( _xx,  _yy);
	}	
	EffectManager::getInstance()->eventClick( _xx,  _yy);

	m_IOData.x = _xx;
	m_IOData.y = _yy;
	m_IOData.isButtonDown = true;
}

void Scene::eventMouseMove(int _xx, int _yy, int x_rel, int y_rel, bool isButtonDown)
{
	std::map<Ogre::String,Sprite*>::iterator it;
	for(it = m_vNpc.begin(); it != m_vNpc.end(); ++it)
	{
		if(it->second)
			it->second->eventMouseMove( _xx,  _yy, x_rel, y_rel, isButtonDown);
	}
	EffectManager::getInstance()->eventMouseMove( _xx,  _yy, x_rel, y_rel, isButtonDown);

	m_IOData.x = _xx;
	m_IOData.y = _yy;
	m_IOData.x_rel = x_rel;
	m_IOData.y_rel = y_rel;
	m_IOData.isButtonDown = isButtonDown;
}

void Scene::eventMouseRelease(int _xx, int _yy)
{
	std::map<Ogre::String,Sprite*>::iterator it;
	for(it = m_vNpc.begin(); it != m_vNpc.end(); ++it)
	{
		if(it->second)
			it->second->eventMouseRelease(_xx, _yy);
	}
	EffectManager::getInstance()->eventMouseRelease(_xx, _yy);

	m_IOData.x = _xx;
	m_IOData.y = _yy;
	m_IOData.isButtonDown = false;
}

void Scene::stateMouseDown()
{
	if (!m_IOData.isButtonDown)
	{
		return;
	}
	std::map<Ogre::String,Sprite*>::iterator it;
	EffectManager::getInstance()->stateMouseDown(m_IOData.x, m_IOData.y, 
		m_IOData.x_rel, m_IOData.y_rel,true);

	for(it = m_vNpc.begin(); it != m_vNpc.end(); ++it)
	{
		if(it->second)
			it->second->stateMouseDown(m_IOData.x, m_IOData.y, 
			m_IOData.x_rel, m_IOData.y_rel,true);
	}
	
}

void Scene::update(Ogre::Real timeSinceLast)
{
	std::map<Ogre::String,Sprite*>::iterator it;
	for(it = m_vNpc.begin(); it != m_vNpc.end(); ++it)
	{
		if(it->second)
			it->second->update(timeSinceLast);
	}

	
	

	EffectManager::getInstance()->update(timeSinceLast);

	//step FX
	int steps = dynamicsWorld->stepSimulation(timeSinceLast,10,0.01f);

	//update registered 
	for(it = m_vNpc.begin(); it != m_vNpc.end(); ++it)
	{
		if(it->second)
			it->second->synchronizeFX();
	}
	
	//if mouse down
	stateMouseDown();

	//deal with events in the end
	EventManager::getInstance()->EventExecuteUpdate();


	/************************************************************************/
	/* bt debug drawer                                                      */
	/************************************************************************/
	//dynamicsWorld->setDebugDrawer(gc);
	//dynamicsWorld->debugDrawWorld();
}

void Scene::_setupCamera()
{
	//create camera
	Ogre::Real _cameraHeight = 1000;
	m_pCamera->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
	m_pCamera->setOrthoWindow(12,8);
	Ogre::Vector3 cameraPosition = Ogre::Vector3(6, _cameraHeight, _cameraHeight + 4 *Ogre::Math::Sqrt(2.0f));
	m_pCamera->setPosition(cameraPosition);
	m_pCamera->setDirection(Ogre::Vector3(0,-1,-1));
	m_pCamera->setNearClipDistance(2);
	m_pCamera->setFarClipDistance(3000);
}

void Scene::_createBackGround()
{
	// Create background material

	Ogre::String TextureName = Ogre::String("thorMap1.jpg");
	Ogre::MaterialPtr _material = Ogre::MaterialManager::getSingleton().create("Background", "General");
	_material->getTechnique(0)->getPass(0)->createTextureUnitState(TextureName);
	_material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
	_material->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
	_material->getTechnique(0)->getPass(0)->setLightingEnabled(false);

	Ogre::ManualObject *_manual = m_pSceneMgr->createManualObject();

	TextureManager::getSingletonPtr()->load(TextureName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	TexturePtr texPtr = TextureManager::getSingletonPtr()->getByName(TextureName);

	Ogre::FloatRect _mapRect;
	_mapRect.left = 0;
	_mapRect.right =texPtr->getWidth();
	_mapRect.top = 0;
	_mapRect.bottom = texPtr->getHeight();
	
	Ogre::Real _y = 0;
	

	_manual->begin("Background", RenderOperation::OT_TRIANGLE_LIST );
	_manual->position( _mapRect.left, _y, _mapRect.top );
	_manual->textureCoord(Vector2(0,0));
	_manual->position( _mapRect.left, _y, _mapRect.bottom );
	_manual->textureCoord(Vector2(0,1));
	_manual->position( _mapRect.right, _y, _mapRect.bottom );
	_manual->textureCoord(Vector2(1,1));
	_manual->position( _mapRect.right, _y, _mapRect.bottom );
	_manual->textureCoord(Vector2(1,1));
	_manual->position( _mapRect.right, _y, _mapRect.top );
	_manual->textureCoord(Vector2(1,0));
	_manual->position( _mapRect.left, _y, _mapRect.top );
	_manual->textureCoord(Vector2(0,0));

	_manual->end();
	_manual->setRenderQueueGroup(RENDER_QUEUE_MAIN - 2);
	
	SceneNode * _node = m_pSceneMgr->getRootSceneNode()->createChildSceneNode();
	_node->attachObject(_manual);
	_node->setScale(Vector3(0.025f,0.025f,0.025f*Math::Sqrt(2.0f)));

	
}

Sprite * Scene::_createOneSprite(Ogre::String _meshName, int type, Ogre::String spriteName)
{
	Sprite * _sprite = new Sprite(m_pSceneMgr, m_pCamera);
	_sprite->mType = type;
	_sprite->init(spriteName);
	_sprite->load(_meshName);
	std::pair<Ogre::String, Sprite *> _pair;
	_pair.first = spriteName;
	_pair.second = _sprite;
	m_vNpc.insert(_pair);
	_sprite->_createShadow(true);
	_sprite->setPosition(Ogre::Vector3(500.0f,0.0f, 300.0f*1.414f));
	_sprite->setOrientation(Ogre::Quaternion::IDENTITY);
	_sprite->setScale(Ogre::Vector3(5,5,5));
	_sprite->mDestination = _sprite->mPosition;
	_sprite->mAngularDestination = Vector3(0,0,1);
	return _sprite;

	
}

void Scene::_createSprites()
{
	
}



void Scene::_createFxWorld()
{
	// Build the broadphase
	btBroadphaseInterface* broadphase = new btDbvtBroadphase();
	// Set up the collision configuration and dispatcher
	collisionConfiguration = new btDefaultCollisionConfiguration();
	dispatcher = new btCollisionDispatcher(collisionConfiguration);

	// The actual physics solver
	solver = new btSequentialImpulseConstraintSolver;

	// The world.
	dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
	dynamicsWorld->setGravity(btVector3(0,-15,0));

	//create ground
	
	
	btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);;
	btDefaultMotionState* groundMotionState =
		new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)));
	btRigidBody::btRigidBodyConstructionInfo
		groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));
	btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);
	dynamicsWorld->addRigidBody(groundRigidBody);
}

Sprite* Scene::getNPCSprite(Ogre::String _spriteName)
{
	std::map<Ogre::String, Sprite*>::iterator it = m_vNpc.find(_spriteName);
	if(it != m_vNpc.end())
		return it->second;
	else
		return NULL;
}